{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "import matplotlib.pyplot as plt\n",
    "plt.style.use('ggplot')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from itertools import chain\n",
    "\n",
    "import nltk\n",
    "import sklearn\n",
    "import scipy.stats\n",
    "from sklearn.metrics import make_scorer\n",
    "from sklearn.model_selection import cross_val_score\n",
    "from sklearn.model_selection import RandomizedSearchCV\n",
    "\n",
    "import sklearn_crfsuite\n",
    "from sklearn_crfsuite import scorers\n",
    "from sklearn_crfsuite import metrics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Let's use CoNLL 2002 data to build a NER system\n",
    "\n",
    "CoNLL2002 corpus is available in NLTK. We use Spanish data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['esp.testa', 'esp.testb', 'esp.train', 'ned.testa', 'ned.testb', 'ned.train']"
      ]
     },
     "execution_count": 2,
     "output_type": "execute_result",
     "metadata": {}
    }
   ],
   "source": [
    "nltk.corpus.conll2002.fileids()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2.91 s, sys: 108 ms, total: 3.02 s\n",
      "Wall time: 3.13 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "train_sents = list(nltk.corpus.conll2002.iob_sents('esp.train'))\n",
    "test_sents = list(nltk.corpus.conll2002.iob_sents('esp.testb'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[('Melbourne', 'NP', 'B-LOC'),\n",
       " ('(', 'Fpa', 'O'),\n",
       " ('Australia', 'NP', 'B-LOC'),\n",
       " (')', 'Fpt', 'O'),\n",
       " (',', 'Fc', 'O'),\n",
       " ('25', 'Z', 'O'),\n",
       " ('may', 'NC', 'O'),\n",
       " ('(', 'Fpa', 'O'),\n",
       " ('EFE', 'NC', 'B-ORG'),\n",
       " (')', 'Fpt', 'O'),\n",
       " ('.', 'Fp', 'O')]"
      ]
     },
     "execution_count": 4,
     "output_type": "execute_result",
     "metadata": {}
    }
   ],
   "source": [
    "train_sents[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Features\n",
    "\n",
    "Next, define some features. In this example we use word identity, word suffix, word shape and word POS tag; also, some information from nearby words is used. \n",
    "\n",
    "This makes a simple baseline, but you certainly can add and remove some features to get (much?) better results - experiment with it.\n",
    "\n",
    "sklearn-crfsuite (and python-crfsuite) supports several feature formats; here we use feature dicts."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def word2features(sent, i):\n",
    "    word = sent[i][0]\n",
    "    postag = sent[i][1]\n",
    "    \n",
    "    features = {\n",
    "        'bias': 1.0,\n",
    "        'word.lower()': word.lower(),\n",
    "        'word[-3:]': word[-3:],\n",
    "        'word[-2:]': word[-2:],\n",
    "        'word.isupper()': word.isupper(),\n",
    "        'word.istitle()': word.istitle(),\n",
    "        'word.isdigit()': word.isdigit(),\n",
    "        'postag': postag,\n",
    "        'postag[:2]': postag[:2],        \n",
    "    }\n",
    "    if i > 0:\n",
    "        word1 = sent[i-1][0]\n",
    "        postag1 = sent[i-1][1]\n",
    "        features.update({\n",
    "            '-1:word.lower()': word1.lower(),\n",
    "            '-1:word.istitle()': word1.istitle(),\n",
    "            '-1:word.isupper()': word1.isupper(),\n",
    "            '-1:postag': postag1,\n",
    "            '-1:postag[:2]': postag1[:2],\n",
    "        })\n",
    "    else:\n",
    "        features['BOS'] = True\n",
    "        \n",
    "    if i < len(sent)-1:\n",
    "        word1 = sent[i+1][0]\n",
    "        postag1 = sent[i+1][1]\n",
    "        features.update({\n",
    "            '+1:word.lower()': word1.lower(),\n",
    "            '+1:word.istitle()': word1.istitle(),\n",
    "            '+1:word.isupper()': word1.isupper(),\n",
    "            '+1:postag': postag1,\n",
    "            '+1:postag[:2]': postag1[:2],\n",
    "        })\n",
    "    else:\n",
    "        features['EOS'] = True\n",
    "                \n",
    "    return features\n",
    "\n",
    "\n",
    "def sent2features(sent):\n",
    "    return [word2features(sent, i) for i in range(len(sent))]\n",
    "\n",
    "def sent2labels(sent):\n",
    "    return [label for token, postag, label in sent]\n",
    "\n",
    "def sent2tokens(sent):\n",
    "    return [token for token, postag, label in sent]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is what word2features extracts:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'+1:postag': 'Fpa',\n",
       " '+1:postag[:2]': 'Fp',\n",
       " '+1:word.istitle()': False,\n",
       " '+1:word.isupper()': False,\n",
       " '+1:word.lower()': '(',\n",
       " 'BOS': True,\n",
       " 'bias': 1.0,\n",
       " 'postag': 'NP',\n",
       " 'postag[:2]': 'NP',\n",
       " 'word.isdigit()': False,\n",
       " 'word.istitle()': True,\n",
       " 'word.isupper()': False,\n",
       " 'word.lower()': 'melbourne',\n",
       " 'word[-2:]': 'ne',\n",
       " 'word[-3:]': 'rne'}"
      ]
     },
     "execution_count": 6,
     "output_type": "execute_result",
     "metadata": {}
    }
   ],
   "source": [
    "sent2features(train_sents[0])[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Extract features from the data:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.48 s, sys: 124 ms, total: 1.61 s\n",
      "Wall time: 1.65 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "X_train = [sent2features(s) for s in train_sents]\n",
    "y_train = [sent2labels(s) for s in train_sents]\n",
    "\n",
    "X_test = [sent2features(s) for s in test_sents]\n",
    "y_test = [sent2labels(s) for s in test_sents]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Training\n",
    "\n",
    "To see all possible CRF parameters check its docstring. Here we are useing L-BFGS training algorithm (it is default) with Elastic Net (L1 + L2) regularization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 32 s, sys: 108 ms, total: 32.1 s\n",
      "Wall time: 32.3 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "crf = sklearn_crfsuite.CRF(\n",
    "    algorithm='lbfgs', \n",
    "    c1=0.1, \n",
    "    c2=0.1, \n",
    "    max_iterations=100, \n",
    "    all_possible_transitions=True\n",
    ")\n",
    "crf.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Evaluation\n",
    "\n",
    "There is much more O entities in data set, but we're more interested in other entities. To account for this we'll use averaged F1 score computed for all labels except for O. ``sklearn-crfsuite.metrics`` package provides some useful metrics for sequence classification task, including this one."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['B-LOC', 'B-ORG', 'B-PER', 'I-PER', 'B-MISC', 'I-ORG', 'I-LOC', 'I-MISC']"
      ]
     },
     "execution_count": 25,
     "output_type": "execute_result",
     "metadata": {}
    }
   ],
   "source": [
    "labels = list(crf.classes_)\n",
    "labels.remove('O')\n",
    "labels"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.76980231377134023"
      ]
     },
     "execution_count": 26,
     "output_type": "execute_result",
     "metadata": {}
    }
   ],
   "source": [
    "y_pred = crf.predict(X_test)\n",
    "metrics.flat_f1_score(y_test, y_pred, \n",
    "                      average='weighted', labels=labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Inspect per-class results in more detail:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             precision    recall  f1-score   support\n",
      "\n",
      "      B-LOC      0.775     0.757     0.766      1084\n",
      "      I-LOC      0.601     0.631     0.616       325\n",
      "     B-MISC      0.698     0.499     0.582       339\n",
      "     I-MISC      0.644     0.567     0.603       557\n",
      "      B-ORG      0.795     0.801     0.798      1400\n",
      "      I-ORG      0.831     0.773     0.801      1104\n",
      "      B-PER      0.812     0.876     0.843       735\n",
      "      I-PER      0.873     0.931     0.901       634\n",
      "\n",
      "avg / total      0.779     0.764     0.770      6178\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# group B and I results\n",
    "sorted_labels = sorted(\n",
    "    labels, \n",
    "    key=lambda name: (name[1:], name[0])\n",
    ")\n",
    "print(metrics.flat_classification_report(\n",
    "    y_test, y_pred, labels=sorted_labels, digits=3\n",
    "))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hyperparameter Optimization\n",
    "\n",
    "To improve quality try to select regularization parameters using randomized search and 3-fold cross-validation.\n",
    "\n",
    "I takes quite a lot of CPU time and RAM (we're fitting a model ``50 * 3 = 150`` times), so grab a tea and be patient, or reduce n_iter in RandomizedSearchCV, or fit model only on a subset of training data."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 3 folds for each of 50 candidates, totalling 150 fits\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Parallel(n_jobs=-1)]: Done  34 tasks      | elapsed:  4.1min\n",
      "[Parallel(n_jobs=-1)]: Done 150 out of 150 | elapsed: 16.1min finished\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 3min 34s, sys: 13.9 s, total: 3min 48s\n",
      "Wall time: 16min 36s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# define fixed parameters and parameters to search\n",
    "crf = sklearn_crfsuite.CRF(\n",
    "    algorithm='lbfgs', \n",
    "    max_iterations=100, \n",
    "    all_possible_transitions=True\n",
    ")\n",
    "params_space = {\n",
    "    'c1': scipy.stats.expon(scale=0.5),\n",
    "    'c2': scipy.stats.expon(scale=0.05),\n",
    "}\n",
    "\n",
    "# use the same metric for evaluation\n",
    "f1_scorer = make_scorer(metrics.flat_f1_score, \n",
    "                        average='weighted', labels=labels)\n",
    "\n",
    "# search\n",
    "rs = RandomizedSearchCV(crf, params_space, \n",
    "                        cv=3, \n",
    "                        verbose=1, \n",
    "                        n_jobs=-1, \n",
    "                        n_iter=50, \n",
    "                        scoring=f1_scorer)\n",
    "rs.fit(X_train, y_train)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Best result:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "best params: {'c2': 0.06146442424219609, 'c1': 0.30343585910230675}\n",
      "best CV score: 0.748852160441\n",
      "model size: 1.08M\n"
     ]
    }
   ],
   "source": [
    "# crf = rs.best_estimator_\n",
    "print('best params:', rs.best_params_)\n",
    "print('best CV score:', rs.best_score_)\n",
    "print('model size: {:0.2f}M'.format(rs.best_estimator_.size_ / 1000000))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Check parameter space\n",
    "\n",
    "A chart which shows which ``c1`` and ``c2`` values have RandomizedSearchCV checked. Red color means better results, blue means worse."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Dark blue => 0.7013, dark red => 0.7489\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuUAAALkCAYAAACoZktbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3Xl4TGf/BvD7nKyTZJLIJoIgKEnUmtZetIputBTVaulC\nQ6u0b5XiVS26b6K0tbT2VtDa1Q+t0lgatbWDiBBCJEKIkUWW+f7+0MxrzCQi28lyf64rFznbfM/M\nPGfuOXnOcxQRERARERERkWZUrQsgIiIiIqruGMqJiIiIiDTGUE5EREREpDGGciIiIiIijTGUExER\nERFpjKGciIiIiEhjDOVUbrp164bhw4eX+eOcPn0aqqpi165dZfo47777Lho3blymj0FUWhYsWAAH\nBwety6jwyrpdh4WFYcWKFSXejqqqWLZsWSlURHRnpk+fjoEDB2pdRpXEUF5NPP/881BVFaqqwt7e\nHgEBAejfvz9iY2O1Lq3UBQYGIikpCW3bti3zx1IUpdD5DRo0wPvvv281/ffff4eqqkhMTCyr0ugm\njRs3xnvvvVemj5GamorXXnsNQUFBcHZ2hp+fH+677z4sX768TB+3qBRFue37tSCZmZmYNm0aWrRo\nAVdXV/j4+KBdu3b46quvkJmZiTFjxqB27dowmUw21w8NDcVzzz1X4Pbzj02qqsLFxQVNmjTBlClT\noNVtNG5+nqZPn44GDRqUynaXLl2KrKws9O/fv8TbSkpKwpNPPlkKVRVuwYIFaNq0KZydnRESEnLb\nLwILFy6Eqqqws7OzeF1VVcWqVavMy+Xm5uKtt95CQEAAXFxc0LlzZ+zfv99iW3PnzkX37t3h4+NT\nLidaKoq9e/eiY8eO0Ol0CAgIwIQJEwptC/knomw956NGjbK5zoIFC6CqKnr06GExPSMjA+PHj0fD\nhg2h0+nQokULi9cNAEaPHo0tW7bgr7/+KvnOkgWG8mrkvvvuQ3JyMhISEhAZGYmYmBg89thjWpdV\n6hRFgZ+fH+zs7LQupVDFDUilLScnp0y3n5ubW6bbL28F7U/fvn3xxx9/YO7cuYiNjcXmzZvx9NNP\n49KlS2VeU1m+hkajER06dMCsWbMwatQo7N69G3/99RfGjh2LFStWYMuWLRg+fDiSkpKwYcMGq/Wj\noqJw7NgxvPzyy4U+zuzZs5GUlISjR4/izTffxPvvv48PP/ywrHaryESk1NrqjBkz8NJLL5XKtvz8\n/ODo6Fgq2yrI6tWr8dJLL2HkyJE4fPgwXnzxRTz33HPYvHlzges89dRTSEpKwvnz55GUlISkpCS8\n/vrr8PDwwMMPP2xe7s0338T333+PuXPnYt++fQgKCkL37t1x4cIF8zIZGRl44IEH8Mknn1SY42VZ\nO3v2LHr06IHg4GDs378f33zzDb799ltMnDixwHXyT0Td/JyvWLECiqJg0KBBVssfOXIEEydORJcu\nXazmDRs2DKtWrcLcuXNx5MgRDBs2DIMGDcLWrVvNy7i5ueHJJ5/EzJkzS2en6X+EqoWhQ4fKgw8+\naDFt5syZoqqqXLp0yTxt2bJl0rZtW/Hw8BAfHx955JFH5Pjx4+b58fHxoiiKREZGyqOPPiouLi4S\nFBQkCxYssNj26dOnpWfPnqLT6SQwMFBmzpwpXbt2lWHDhpmXMRqNMnz4cPH19RUnJycJCwuT//u/\n/7N6rGXLlknPnj3FxcVFgoODZefOnXLmzBnp1auXuLq6SkhIiOzcudNqvaioKPO+K4pi9fPuu++a\n1/nhhx+kZcuW4uzsLPXr15c33nhD0tPTzfOzsrIkPDxcPDw8xMvLS0aMGCFvv/22NG7cuNDnvX79\n+jJ9+nSr6du3bxdVVeXcuXMiIhIUFCQffPCBxTLp6eni7u4uS5YsERGRrl27ygsvvCDjx48XHx8f\ncXd3l+HDh8v169ct1ouIiJCmTZuKs7Oz3HXXXTJ9+nTJzc21qGnSpEkycuRI8fb2lnbt2omIiKIo\nMmPGDOnXr5+4urpK7dq1ZcaMGRbbnjFjhrRs2VLc3NzE399fnnrqKTl//rzFfimKIhs2bJBOnTqJ\nTqeTb775Ri5fviyDBw+WwMBA0el00qRJE/nss88stj106FDp3r27zJw5U+rUqSNubm4SHh4uubm5\nMnPmTAkMDJQaNWrI8OHDJScn57b7nJeXZ37eFEURVVXN/54+fVpERGJjY6Vfv37i6ekpNWrUkB49\nesjff/9t3u6CBQvE3t5efvvtN2nVqpU4OTnJL7/8YvV6Xrlyxbzft3O716eobXDp0qXy8MMPi6ur\nq4wfP15ERE6cOCH9+vUTLy8vcXFxkRYtWphrWrBggTg4OEhUVJS0bt1aXFxcpE2bNhIdHV1ova++\n+qq4uLiYn7NbpaWliYhIp06d5LHHHrOaP2TIEAkJCSn0MfL352Zt2rSx2l7+/hX0el29elWGDh0q\n/v7+4uTkJIGBgfKf//zHPP/WY5CIyLRp06R+/frm36dMmWJu1wsWLLB67+QfN1avXi2tWrUSFxcX\n8fT0lLZt28rBgwcL3MeYmBhRFEVOnTplte8zZ86UgQMHiqurq9SrV09++uknuXz5sgwaNEj0er0E\nBQXJqlWrCn3OFEWR2bNny7PPPit6vV7q1KljdUy5Ux06dJDBgwdbTOvfv79069atyNvIy8uTwMBA\nGTVqlHna1atXxdnZWebNm2exnL+/v8VxOd+tx/Q71bVrV3nxxRdl0qRJ4uvrK56enjJ58mQxmUwy\nefJkqVmzpvj6+srEiRMt1rtdW4yMjBRHR0eLNrRw4ULR6XQW78s78fbbb0vdunUtps2aNUvc3Nwk\nIyOjyNt5+umnpVmzZlbTMzIypFmzZrJ8+XKrXJCVlSUODg4SGRlpsU6fPn2ka9euFtM2btworq6u\nVp8/VDIM5dXErY3v3Llz0qVLF6tQuWDBAlm/fr2cOnVKDh48KH369JHGjRubQ1D+wbFhw4aycuVK\niYuLkwkTJoi9vb3Exsaat9OqVSu59957JTo6Wg4dOiQPPviguLu7W3wgPvnkk9KgQQPZsmWLHDt2\nTEaPHi2Ojo4SExNj8ViNGjWStWvXSmxsrDzxxBNSu3Zt6datm6xevVpiY2PlySeflMDAQHOwiY+P\nF1VVzQfwq1evSnJysvlnzpw54uDgIL/99puIiHz//ffi5eUlS5culfj4eNm5c6e0aNFCnnvuOXOt\nY8aMkZo1a8q6deskJiZG3nzzTXF3dy92KP/tt98sQvkHH3wgjRo1slhm3rx54u3tLdnZ2SJy44Ml\nP4gfO3ZM1q9fL35+fvLGG2+Y13nnnXekfv36smbNGomPj5dNmzZJvXr1ZPLkyRY1eXh4yLvvviux\nsbFy9OhREbnxoe7t7S2zZs2S2NhYiYiIEHt7e1m7dq153YiICNm2bZvEx8fLnj17pGPHjhYH6/xQ\nHhwcLOvXr5f4+Hg5d+6cJCUlyUcffSQHDx6U+Ph4Wbp0qej1eosvc0OHDhV3d3cZOnSoef+cnZ2l\nZ8+eMmTIEDl27Jhs3LjRHPSLus+pqanSoEEDGTt2rPk9YDKZJDk5Wfz9/eWVV14Rg8Egx48fl9de\ne018fHzk4sWLInKjPaiqKm3btpXt27fLqVOnzPNulpuba35tbv4yd6uivD5FbYN169aVZcuWSXx8\n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\nbkwxcuRIvPTSS0W+aQv9T0U+MAEM5aW1nap0cKoqKvpzxmBQOtth26uYKvLzxrZXOtupSm1P0ws9\nU1JS8NH6uCtOAAAgAElEQVRHH+HTTz8FcGOInUOHDpmHUNqxYwdOnDhR4PjRtzIYDBZPnq0h5YiI\niIiIykJkZKT5/6GhoYUOlXqrCnXzIC8vL1y8eNH8e2pqapHuGpbP1s7feqMIIip7er2+wLsXElHZ\nYdsj0k5AQECJTghr2n1FRCwu2mzUqBGSkpKQkpKC3NxcREVFISwsTMMKiYiIiIjKnmbdV2bMmIEj\nR47AaDTCw8MDAwYMQLdu3XDgwAEsWLAAIoL7778fjz/+eIkeh2fKicofz9YRaYNtj0g7AQEBJVq/\n0tw8qLgYyonKH4MBkTbY9oi0U9JQXqFGXyEiIiIiqo4YyomIiIiINMZQTkRERESksSoZyg0Gg8U4\nkUREREREZS0yMrLYNxzihZ5EVOp4sRmRNtj2iLTDCz2JiIiIiCo5hnIiIiIiIo0xlBMRERERaYyh\nnIiIiIhIYwzlREREREQaYygnIiIiItJYlQzlHKeciIiIiMobxykvBMcpJyp/HCuZSBtse0Ta4Tjl\nRERERESVHEM5EREREZHGGMqJiIiIiDTGUE5EREREpDGGciIiIiIijTGUExERERFpjKGciIiIiEhj\nDOVERERERBqrkqGcd/QkIiIiovLGO3oWgnf0JCp/vKsgkTbY9oi0wzt6EhERERFVcgzlREREREQa\nYygnIiIiItIYQzkRERERkcYYyomIiIiINMZQTkRERESkMYZyIiIiIiKNMZQTEREREWmMoZyIiIiI\nSGNVMpQbDAZERkZqXQYRERERVSORkZEwGAzFWlcRESnleiqUxMRErUsgqnZ4q28ibbDtEWknICCg\nROtXyTPlRERERESVCUM5EREREZHGGMqJiIiIiDTGUE5EREREpDGGciIiIiIijTGUExERERFpjKGc\niIiIiEhjDOVERERERBpjKCciIiIi0hhDORERERGRxhjKiYiIiIg0ViVDucFgQGRkpNZlEBEREVE1\nEhkZCYPBUKx1FRGRUq6nQklMTNS6BKJqR6/Xw2g0al0GUbXDtkeknYCAgBKtXyXPlBMRERERVSYM\n5UREREREGmMoJyIiIiLSGEM5EREREZHGGMqJiIiIiDTGUE5EREREpDGGciIiIiIijTGUExERERFp\n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\n"
     },
     "output_type": "display_data",
     "metadata": {}
    }
   ],
   "source": [
    "_x = [s.parameters['c1'] for s in rs.grid_scores_]\n",
    "_y = [s.parameters['c2'] for s in rs.grid_scores_]\n",
    "_c = [s.mean_validation_score for s in rs.grid_scores_]\n",
    "\n",
    "fig = plt.figure()\n",
    "fig.set_size_inches(12, 12)\n",
    "ax = plt.gca()\n",
    "ax.set_yscale('log')\n",
    "ax.set_xscale('log')\n",
    "ax.set_xlabel('C1')\n",
    "ax.set_ylabel('C2')\n",
    "ax.set_title(\"Randomized Hyperparameter Search CV Results (min={:0.3}, max={:0.3})\".format(\n",
    "    min(_c), max(_c)\n",
    "))\n",
    "\n",
    "ax.scatter(_x, _y, c=_c, s=60, alpha=0.9, edgecolors=[0,0,0])\n",
    "\n",
    "print(\"Dark blue => {:0.4}, dark red => {:0.4}\".format(min(_c), max(_c)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Check best estimator on our test data\n",
    "\n",
    "As you can see, quality is improved."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "             precision    recall  f1-score   support\n",
      "\n",
      "      B-LOC      0.800     0.780     0.790      1084\n",
      "      I-LOC      0.663     0.625     0.643       325\n",
      "     B-MISC      0.729     0.555     0.630       339\n",
      "     I-MISC      0.709     0.582     0.639       557\n",
      "      B-ORG      0.808     0.824     0.816      1400\n",
      "      I-ORG      0.849     0.783     0.814      1104\n",
      "      B-PER      0.836     0.882     0.858       735\n",
      "      I-PER      0.884     0.942     0.912       634\n",
      "\n",
      "avg / total      0.804     0.781     0.791      6178\n",
      "\n"
     ]
    }
   ],
   "source": [
    "crf = rs.best_estimator_\n",
    "y_pred = crf.predict(X_test)\n",
    "print(metrics.flat_classification_report(\n",
    "    y_test, y_pred, labels=sorted_labels, digits=3\n",
    "))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Let's check what classifier learned"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Top likely transitions:\n",
      "B-ORG  -> I-ORG   7.029925\n",
      "I-ORG  -> I-ORG   6.672091\n",
      "B-MISC -> I-MISC  6.450077\n",
      "I-MISC -> I-MISC  6.420227\n",
      "B-PER  -> I-PER   5.898448\n",
      "B-LOC  -> I-LOC   5.293131\n",
      "I-LOC  -> I-LOC   4.669233\n",
      "I-PER  -> I-PER   4.327948\n",
      "O      -> O       3.773498\n",
      "O      -> B-ORG   2.723333\n",
      "O      -> B-PER   2.298990\n",
      "O      -> B-LOC   1.753950\n",
      "O      -> B-MISC  1.608865\n",
      "B-ORG  -> O       0.373792\n",
      "B-LOC  -> B-LOC   0.363950\n",
      "B-MISC -> B-ORG   0.213808\n",
      "B-ORG  -> B-LOC   0.122352\n",
      "I-PER  -> B-LOC   0.055117\n",
      "B-LOC  -> B-PER   -0.141696\n",
      "B-MISC -> O       -0.170980\n",
      "\n",
      "Top unlikely transitions:\n",
      "I-ORG  -> B-LOC   -2.281004\n",
      "I-LOC  -> I-PER   -2.285589\n",
      "I-MISC -> B-LOC   -2.286738\n",
      "I-LOC  -> B-MISC  -2.299090\n",
      "B-LOC  -> B-MISC  -2.312090\n",
      "I-ORG  -> I-PER   -2.636941\n",
      "I-ORG  -> B-MISC  -2.673906\n",
      "B-ORG  -> B-MISC  -2.735029\n",
      "I-PER  -> B-ORG   -2.822961\n",
      "B-PER  -> B-MISC  -2.857271\n",
      "I-MISC -> I-LOC   -2.902497\n",
      "I-PER  -> I-LOC   -2.931078\n",
      "I-ORG  -> I-LOC   -2.943800\n",
      "B-PER  -> B-PER   -3.063315\n",
      "I-PER  -> B-MISC  -3.373836\n",
      "B-MISC -> B-MISC  -3.435245\n",
      "O      -> I-MISC  -5.385205\n",
      "O      -> I-ORG   -5.670565\n",
      "O      -> I-PER   -6.003255\n",
      "O      -> I-LOC   -6.680094\n"
     ]
    }
   ],
   "source": [
    "from collections import Counter\n",
    "\n",
    "def print_transitions(trans_features):\n",
    "    for (label_from, label_to), weight in trans_features:\n",
    "        print(\"%-6s -> %-7s %0.6f\" % (label_from, label_to, weight))\n",
    "\n",
    "print(\"Top likely transitions:\")\n",
    "print_transitions(Counter(crf.transition_features_).most_common(20))\n",
    "\n",
    "print(\"\\nTop unlikely transitions:\")\n",
    "print_transitions(Counter(crf.transition_features_).most_common()[-20:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can see that, for example, it is very likely that the beginning of an organization name (B-ORG) will be followed by a token inside organization name (I-ORG), but transitions to I-ORG from tokens with other labels are penalized.\n",
    "\n",
    "Check the state features:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Top positive:\n",
      "11.005266 B-ORG    word.lower():efe-cantabria\n",
      "9.385823 B-ORG    word.lower():psoe-progresistas\n",
      "6.715219 I-ORG    -1:word.lower():l\n",
      "5.638921 O        BOS\n",
      "5.378117 B-LOC    -1:word.lower():cantabria\n",
      "5.302705 B-ORG    word.lower():xfera\n",
      "5.287491 B-ORG    word[-2:]:-e\n",
      "5.239806 B-ORG    word.lower():petrobras\n",
      "5.214013 B-MISC   word.lower():diversia\n",
      "5.025534 B-ORG    word.lower():coag-extremadura\n",
      "5.020590 B-ORG    word.lower():telefónica\n",
      "4.804399 B-MISC   word.lower():justicia\n",
      "4.729711 B-MISC   word.lower():competencia\n",
      "4.705013 O        postag[:2]:Fp\n",
      "4.695208 B-ORG    -1:word.lower():distancia\n",
      "4.681021 I-ORG    -1:word.lower():rasd\n",
      "4.636151 I-LOC    -1:word.lower():calle\n",
      "4.618459 B-ORG    word.lower():terra\n",
      "4.580418 B-PER    -1:word.lower():según\n",
      "4.574348 B-ORG    word.lower():esquerra\n",
      "4.537127 O        word.lower():r.\n",
      "4.537127 O        word[-3:]:R.\n",
      "4.536578 B-MISC   word.lower():cc2305001730\n",
      "4.510408 B-ORG    +1:word.lower():plasencia\n",
      "4.471889 B-LOC    +1:word.lower():finalizaron\n",
      "4.451102 B-LOC    word.lower():líbano\n",
      "4.423293 B-ORG    word.isupper()\n",
      "4.379665 O        word.lower():euro\n",
      "4.361340 B-LOC    -1:word.lower():celebrarán\n",
      "4.345542 I-MISC   -1:word.lower():1.9\n",
      "\n",
      "Top negative:\n",
      "-2.006512 I-PER    word[-3:]:ión\n",
      "-2.020133 B-PER    word[-2:]:os\n",
      "-2.027996 O        +1:word.lower():campo\n",
      "-2.028221 O        +1:word.lower():plasencia\n",
      "-2.043293 O        word.lower():061\n",
      "-2.097561 O        postag:NP\n",
      "-2.097561 O        postag[:2]:NP\n",
      "-2.115992 O        word[-3:]:730\n",
      "-2.156136 O        word.lower():circo\n",
      "-2.173247 B-LOC    word[-3:]:la\n",
      "-2.223739 I-PER    +1:word.lower():del\n",
      "-2.323688 B-MISC   -1:word.isupper()\n",
      "-2.347859 O        -1:word.lower():sánchez\n",
      "-2.378442 I-PER    word[-3:]:ico\n",
      "-2.404641 I-PER    +1:word.lower():el\n",
      "-2.414000 O        word[-3:]:bas\n",
      "-2.495209 O        -1:word.lower():británica\n",
      "-2.539839 B-PER    word[-3:]:nes\n",
      "-2.596765 O        +1:word.lower():justicia\n",
      "-2.621004 O        -1:word.lower():sección\n",
      "-2.981810 O        word[-3:]:LOS\n",
      "-3.046486 O        word[-2:]:nd\n",
      "-3.162064 O        -1:word.lower():españolas\n",
      "-3.219096 I-PER    -1:word.lower():san\n",
      "-3.562049 B-PER    -1:word.lower():del\n",
      "-3.580405 O        word.lower():mas\n",
      "-4.119731 O        word[-2:]:om\n",
      "-4.301704 O        -1:word.lower():celebrarán\n",
      "-5.632036 O        word.isupper()\n",
      "-8.215073 O        word.istitle()\n"
     ]
    }
   ],
   "source": [
    "def print_state_features(state_features):\n",
    "    for (attr, label), weight in state_features:\n",
    "        print(\"%0.6f %-8s %s\" % (weight, label, attr))    \n",
    "\n",
    "print(\"Top positive:\")\n",
    "print_state_features(Counter(crf.state_features_).most_common(30))\n",
    "\n",
    "print(\"\\nTop negative:\")\n",
    "print_state_features(Counter(crf.state_features_).most_common()[-30:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "\n",
    "Some observations:\n",
    "\n",
    "   * **9.385823 B-ORG word.lower():psoe-progresistas** - the model remembered names of some entities - maybe it is overfit, or maybe our features are not adequate, or maybe remembering is indeed helpful;\n",
    "   * **4.636151 I-LOC -1:word.lower():calle:** \"calle\" is a street in Spanish; model learns that if a previous word was \"calle\" then the token is likely a part of location;\n",
    "   * **-5.632036 O word.isupper()**, **-8.215073 O word.istitle()** : UPPERCASED or TitleCased words are likely entities of some kind;\n",
    "   * **-2.097561 O postag:NP** - proper nouns (NP is a proper noun in the Spanish tagset) are often entities.\n",
    "\n",
    "What to do next\n",
    "\n",
    "    * Load 'testa' Spanish data.\n",
    "    * Use it to develop better features and to find best model parameters.\n",
    "    * Apply the model to 'testb' data again.\n",
    "\n",
    "The model in this notebook is just a starting point; you certainly can do better!\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    ""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3.0
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.4.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
